summaryrefslogtreecommitdiffstats
path: root/src/core/file_sys/fsa/fs_i_directory.h
blob: a4135efec09ac8132fc4cbbfb4019c82b1902677 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "common/common_types.h"
#include "core/file_sys/errors.h"
#include "core/file_sys/fs_directory.h"
#include "core/file_sys/fs_file.h"
#include "core/file_sys/fs_filesystem.h"
#include "core/file_sys/savedata_factory.h"
#include "core/file_sys/vfs/vfs.h"
#include "core/hle/result.h"

namespace FileSys::Fsa {

class IDirectory {
public:
    IDirectory(VirtualDir backend_, OpenDirectoryMode mode) : backend(std::move(backend_)) {
        // TODO(DarkLordZach): Verify that this is the correct behavior.
        // Build entry index now to save time later.
        if (True(mode & OpenDirectoryMode::Directory)) {
            BuildEntryIndex(entries, backend->GetSubdirectories(), DirectoryEntryType::Directory);
        }
        if (True(mode & OpenDirectoryMode::File)) {
            BuildEntryIndex(entries, backend->GetFiles(), DirectoryEntryType::File);
        }
    }
    virtual ~IDirectory() {}

    Result Read(s64* out_count, DirectoryEntry* out_entries, s64 max_entries) {
        R_UNLESS(out_count != nullptr, ResultNullptrArgument);
        if (max_entries == 0) {
            *out_count = 0;
            R_SUCCEED();
        }
        R_UNLESS(out_entries != nullptr, ResultNullptrArgument);
        R_UNLESS(max_entries > 0, ResultInvalidArgument);
        R_RETURN(this->DoRead(out_count, out_entries, max_entries));
    }

    Result GetEntryCount(s64* out) {
        R_UNLESS(out != nullptr, ResultNullptrArgument);
        R_RETURN(this->DoGetEntryCount(out));
    }

private:
    virtual Result DoRead(s64* out_count, DirectoryEntry* out_entries, s64 max_entries) {
        const u64 actual_entries =
            std::min(static_cast<u64>(max_entries), entries.size() - next_entry_index);
        auto* begin = reinterpret_cast<u8*>(entries.data() + next_entry_index);

        next_entry_index += actual_entries;
        *out_count = actual_entries;

        out_entries = reinterpret_cast<DirectoryEntry*>(begin);

        R_SUCCEED();
    }

    virtual Result DoGetEntryCount(s64* out) {
        *out = entries.size() - next_entry_index;
        R_SUCCEED();
    }

    // TODO: Remove this when VFS is gone
    template <typename T>
    void BuildEntryIndex(std::vector<DirectoryEntry>& entries, const std::vector<T>& new_data,
                         DirectoryEntryType type) {
        entries.reserve(entries.size() + new_data.size());

        for (const auto& new_entry : new_data) {
            auto name = new_entry->GetName();

            if (type == DirectoryEntryType::File && name == GetSaveDataSizeFileName()) {
                continue;
            }

            entries.emplace_back(name, static_cast<s8>(type),
                                 type == DirectoryEntryType::Directory ? 0 : new_entry->GetSize());
        }
    }

    VirtualDir backend;
    std::vector<DirectoryEntry> entries;
    u64 next_entry_index = 0;
};

} // namespace FileSys::Fsa